// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0

import { HorizontalBox, Palette, ScrollView } from "std-widgets.slint";
import { ComponentListItem, ComponentItem } from "../api.slint";
import { StateLayer } from "./state-layer.slint";
import { EditorSizeSettings, EditorAnimationSettings, Icons } from "./styling.slint";
import { BodyText } from "./body-text.slint";
import { BodyStrongText } from "./body-strong-text.slint";
import { StatusLineApi } from "status-line.slint";

component HeaderItemTemplate {
    in property <bool> enabled: true;
    in property <string> text;
    out property <bool> open: true;
    out property <length> offset: icon-image.width + content-layer.spacing;

    min-width: content-layer.min-width;
    min-height: max(EditorSizeSettings.item-height, content-layer.min-height);

    touch-area := TouchArea {
        clicked => {
            root.open = !root.open;
        }
    }

    state-layer := StateLayer {
        width: 100%;
        height: 100%;
        has-hover: touch-area.has-hover;
        pressed: touch-area.pressed;
    }

    content-layer := HorizontalBox {
        icon-image := Image {
            width: EditorSizeSettings.default-icon-width;
            colorize: Palette.foreground;
            source: Icons.chevron-down;
            rotation-origin-x: self.width / 2;
            rotation-origin-y: self.height / 2;
            states [
                closed when !root.open: {
                    rotation-angle: -0.25turn;
                }
            ]

            animate rotation-angle { duration: EditorAnimationSettings.rotation-duration; }
        }

        BodyText {
            text: root.text;
            opacity: 0.7;
        }
    }

    states [
        disabled when !root.enabled: {
            root.opacity: 0.5;
        }
    ]
}

component ItemTemplate {
    in property <bool> enabled: true;
    in property <string> text;
    in property <bool> can-drop-here;
    in property <length> offset;
    out property <length> absolute-mouse-x: touch-area.mouse-x - touch-area.x + touch-area.absolute-position.x;
    out property <length> absolute-mouse-y: touch-area.mouse-y - touch-area.y + touch-area.absolute-position.y;
    out property <bool> pressed <=> touch-area.pressed;

    callback clicked <=> touch-area.clicked;
    callback pointer-event <=> touch-area.pointer-event;

    min-width: content-layer.min-width;
    min-height: max(EditorSizeSettings.item-height, content-layer.min-height);

    touch-area := TouchArea {
        states [
            dragging-no-drop when self.pressed && !root.can-drop-here: {
                mouse-cursor: MouseCursor.no-drop;
            }
            dragging-can-drop when self.pressed && root.can-drop-here: {
                mouse-cursor: MouseCursor.copy;
            }
            normal when !self.pressed: {
                mouse-cursor: MouseCursor.default;
            }
        ]

        changed has-hover => {
            if self.has-hover {
                StatusLineApi.help-text = @tr("Drag onto canvas to add {}", text);
            }
        }
    }

    state-layer := StateLayer {
        width: 100%;
        height: 100%;
        has-hover: touch-area.has-hover;
        pressed: touch-area.pressed;
    }

    content-layer := HorizontalBox {
        padding-left: self.padding + root.offset;
        BodyText {
            text: root.text;
        }
    }

    states [
        disabled when !root.enabled: {
            root.opacity: 0.5;
        }
    ]
}

export component ExpandableListView inherits ScrollView {
    in property <[ComponentListItem]> known-components;

    in property <bool> preview-is-current;
    in property <length> preview-area-position-x;
    in property <length> preview-area-position-y;
    in property <length> preview-area-width;
    in property <length> preview-area-height;
    in-out property <ComponentItem> visible-component: {
        name: "",
        defined-at: "",
        pretty-location: "",
        is-user-defined: false,
        is-currently-shown: false,
    };

    pure callback can-drop(index: int, x: length, y: length, on-drop-area: bool) -> bool;
    callback drop(index: int, x: length, y: length);
    callback show-preview-for(name: string, defined-at: string);

    property <bool> preview-visible: preview-area-width > 0px && preview-area-height > 0px;
    property <length> list-spacing: 10px;

    VerticalLayout {
        alignment: start;
        for cli[index] in root.known-components: VerticalLayout {
            property <int> my-category-index: index;
            header-item := HeaderItemTemplate {
                text: cli.category;
            }

            if header-item.open: VerticalLayout {
                for ci[index] in cli.components: ItemTemplate {
                    property <length> drop-x: self.absolute-mouse-x - root.preview-area-position-x;
                    property <length> drop-y: self.absolute-mouse-y - root.preview-area-position-y;
                    property <bool> on-drop-area:
                            drop-x >= 0 && drop-x <= root.preview-area-width && drop-y >= 0 && drop-y <= root.preview-area-height;
                    property <ComponentItem> data: ci;

                    can-drop-here: root.preview-is-current && !self.data.is-currently-shown && root.can-drop(self.data.index, drop-x, drop-y, on-drop-area);
                    enabled: root.preview-visible;
                    text: ci.name;
                    offset: header-item.offset;
                    height: self.min-height;

                    pointer-event(event) => {
                        if self.can-drop-here && event.kind == PointerEventKind.up && event.button == PointerEventButton.left {
                            root.drop(self.data.index, drop-x, drop-y);
                        }
                    }

                    init() => {
                        root.visible-component = ci;
                    }
                }
            }
        }
    }
}
